# -*- coding: utf-8 -*-
"""
虚拟文件系统模型
@api-version: 1.0.0
// REF: API-NETDISK-002
"""

from datetime import datetime
from . import db
from .user import User
from .virtual_storage import VirtualStorage
import json

class VirtualFile(db.Model):
    """虚拟文件系统模型
    
    用于管理用户的文件和文件夹结构
    每个用户拥有独立的文件系统空间
    """
    __tablename__ = 'virtual_files'
    
    id = db.Column(db.Integer, primary_key=True, comment='节点ID')
    name = db.Column(db.String(255), nullable=False, comment='文件/文件夹名称')
    parent_id = db.Column(db.Integer, db.ForeignKey('virtual_files.id'), comment='父目录ID')
    is_folder = db.Column(db.Boolean, nullable=False, default=False, comment='是否为文件夹')
    storage_file_id = db.Column(db.String(64), db.ForeignKey('virtual_storage.file_id'), comment='关联的存储文件ID')
    file_size = db.Column(db.BigInteger, default=0, comment='文件大小（字节，冗余字段）')
    sort_order = db.Column(db.Integer, default=0, comment='排序顺序')
    description = db.Column(db.Text, comment='描述信息')
    tags = db.Column(db.JSON, comment='标签（JSON格式）')
    is_favorite = db.Column(db.Boolean, default=False, comment='是否收藏')
    is_hidden = db.Column(db.Boolean, default=False, comment='是否隐藏')
    access_count = db.Column(db.Integer, default=0, comment='访问次数')
    last_access_time = db.Column(db.DateTime, comment='最后访问时间')
    created_at = db.Column(db.DateTime, nullable=False, default=datetime.utcnow, comment='创建时间')
    updated_at = db.Column(db.DateTime, nullable=False, default=datetime.utcnow, 
                          onupdate=datetime.utcnow, comment='更新时间')
    owner_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False, comment='所属用户ID')
    
    # 关联关系
    parent = db.relationship('VirtualFile', remote_side=[id], backref='children')
    owner = db.relationship('User', backref='virtual_files')
    
    # 表级约束
    __table_args__ = (
        db.UniqueConstraint('name', 'parent_id', 'owner_id', name='uk_files_name_parent_owner'),
        db.CheckConstraint('char_length(name) >= 1 AND char_length(name) <= 255', name='chk_files_name_length'),
        db.CheckConstraint('file_size >= 0', name='chk_files_file_size'),
        db.CheckConstraint('access_count >= 0', name='chk_files_access_count'),
    )
    
    def __init__(self, name, owner_id, parent_id=None, is_folder=False, 
                 storage_file_id=None, file_size=0, description=None):
        self.name = name
        self.owner_id = owner_id
        self.parent_id = parent_id
        self.is_folder = is_folder
        self.storage_file_id = storage_file_id
        self.file_size = file_size if not is_folder else 0
        self.description = description
        self.tags = []
        self.is_favorite = False
        self.is_hidden = False
        self.access_count = 0
        self.sort_order = 0
    
    def get_full_path(self):
        """获取完整路径"""
        if not self.parent_id:
            return f"/{self.name}"
        
        path_parts = []
        current = self
        
        while current:
            path_parts.append(current.name)
            current = current.parent
            # 防止无限循环
            if len(path_parts) > 50:
                break
        
        path_parts.reverse()
        return "/" + "/".join(path_parts)
    
    def get_depth(self):
        """获取文件夹深度"""
        depth = 0
        current = self.parent
        
        while current:
            depth += 1
            current = current.parent
            # 防止无限循环
            if depth > 50:
                break
        
        return depth
    
    def can_move_to(self, target_parent_id):
        """检查是否可以移动到目标目录"""
        # 不能移动到自己
        if target_parent_id == self.id:
            return False, "不能移动到自己"
        
        # 不能移动到自己的子目录
        if self.is_folder and target_parent_id:
            target_parent = VirtualFile.query.get(target_parent_id)
            if target_parent and target_parent.owner_id != self.owner_id:
                return False, "目标目录不存在或无权限"
            
            # 检查是否是子目录
            current = target_parent
            while current:
                if current.id == self.id:
                    return False, "不能移动到子目录"
                current = current.parent
                # 防止无限循环
                if current and current.get_depth() > 50:
                    break
        
        # 检查目标目录深度限制
        if target_parent_id:
            target_parent = VirtualFile.query.get(target_parent_id)
            if target_parent and target_parent.get_depth() >= 9:  # 最大10层
                return False, "目录层级过深"
        
        # 检查同名文件
        existing = VirtualFile.query.filter_by(
            name=self.name,
            parent_id=target_parent_id,
            owner_id=self.owner_id
        ).filter(VirtualFile.id != self.id).first()
        
        if existing:
            return False, "目标目录已存在同名文件"
        
        return True, "可以移动"
    
    def move_to(self, target_parent_id, new_name=None):
        """移动文件到目标目录"""
        can_move, message = self.can_move_to(target_parent_id)
        if not can_move:
            raise ValueError(message)
        
        self.parent_id = target_parent_id
        if new_name:
            self.name = new_name
        self.updated_at = datetime.utcnow()
        db.session.commit()
    
    def copy_to(self, target_parent_id, new_name=None):
        """复制文件到目标目录"""
        if self.is_folder:
            raise ValueError("暂不支持复制文件夹")
        
        copy_name = new_name or f"{self.name}_副本"
        
        # 检查同名文件
        existing = VirtualFile.query.filter_by(
            name=copy_name,
            parent_id=target_parent_id,
            owner_id=self.owner_id
        ).first()
        
        if existing:
            # 自动生成新名称
            base_name, ext = self._split_filename(copy_name)
            counter = 1
            while existing:
                copy_name = f"{base_name}({counter}){ext}"
                existing = VirtualFile.query.filter_by(
                    name=copy_name,
                    parent_id=target_parent_id,
                    owner_id=self.owner_id
                ).first()
                counter += 1
        
        # 创建副本
        copy_file = VirtualFile(
            name=copy_name,
            owner_id=self.owner_id,
            parent_id=target_parent_id,
            is_folder=False,
            storage_file_id=self.storage_file_id,
            file_size=self.file_size,
            description=self.description
        )
        
        # 复制标签
        if self.tags:
            copy_file.tags = self.tags.copy()
        
        db.session.add(copy_file)
        db.session.commit()
        
        # 增加存储引用计数
        if self.storage_file:
            self.storage_file.increment_reference()
        
        return copy_file
    
    def delete_recursive(self):
        """递归删除文件或文件夹"""
        deleted_files = []
        
        if self.is_folder:
            # 递归删除子项
            for child in self.children:
                deleted_files.extend(child.delete_recursive())
        else:
            # 减少存储引用计数
            if self.storage_file:
                self.storage_file.decrement_reference()
            deleted_files.append(self.id)
        
        db.session.delete(self)
        return deleted_files
    
    def increment_access(self):
        """增加访问计数"""
        self.access_count += 1
        self.last_access_time = datetime.utcnow()
        db.session.commit()
    
    def add_tag(self, tag):
        """添加标签"""
        if not self.tags:
            self.tags = []
        if tag not in self.tags:
            self.tags.append(tag)
            db.session.commit()
    
    def remove_tag(self, tag):
        """移除标签"""
        if self.tags and tag in self.tags:
            self.tags.remove(tag)
            db.session.commit()
    
    def toggle_favorite(self):
        """切换收藏状态"""
        self.is_favorite = not self.is_favorite
        self.updated_at = datetime.utcnow()
        db.session.commit()
    
    def toggle_hidden(self):
        """切换隐藏状态"""
        self.is_hidden = not self.is_hidden
        self.updated_at = datetime.utcnow()
        db.session.commit()
    
    def get_children_count(self):
        """获取子项数量"""
        if not self.is_folder:
            return 0
        return VirtualFile.query.filter_by(parent_id=self.id).count()
    
    def get_folder_size(self):
        """获取文件夹总大小（递归计算）"""
        if not self.is_folder:
            return self.file_size
        
        total_size = 0
        for child in self.children:
            if child.is_folder:
                total_size += child.get_folder_size()
            else:
                total_size += child.file_size
        
        return total_size
    
    @staticmethod
    def _split_filename(filename):
        """分离文件名和扩展名"""
        if '.' in filename:
            parts = filename.rsplit('.', 1)
            return parts[0], f".{parts[1]}"
        return filename, ""
    
    @staticmethod
    def create_root_folder(owner_id):
        """为用户创建根目录"""
        root_folder = VirtualFile(
            name="我的文件",
            owner_id=owner_id,
            parent_id=None,
            is_folder=True,
            description="用户根目录"
        )
        db.session.add(root_folder)
        db.session.commit()
        return root_folder
    
    @staticmethod
    def get_user_root(owner_id):
        """获取用户根目录"""
        root = VirtualFile.query.filter_by(
            owner_id=owner_id,
            parent_id=None,
            is_folder=True
        ).first()
        
        if not root:
            root = VirtualFile.create_root_folder(owner_id)
        
        return root
    
    def to_dict(self, include_children=False, include_path=False):
        """转换为字典格式"""
        data = {
            'id': self.id,
            'name': self.name,
            'parentId': self.parent_id,
            'isFolder': self.is_folder,
            'fileSize': self.file_size,
            'sortOrder': self.sort_order,
            'description': self.description,
            'tags': self.tags or [],
            'isFavorite': self.is_favorite,
            'isHidden': self.is_hidden,
            'accessCount': self.access_count,
            'lastAccessTime': self.last_access_time.isoformat() if self.last_access_time else None,
            'createdAt': self.created_at.isoformat() if self.created_at else None,
            'updatedAt': self.updated_at.isoformat() if self.updated_at else None,
            'ownerId': self.owner_id
        }
        
        # 文件特有信息
        if not self.is_folder and self.storage_file:
            storage_data = self.storage_file.to_dict()
            data.update({
                'storageFileId': self.storage_file_id,
                'originalFilename': storage_data.get('originalFilename'),
                'fileExtension': storage_data.get('fileExtension'),
                'mediaType': storage_data.get('mediaType'),
                'mediaTypeName': storage_data.get('mediaTypeName'),
                'downloadCount': storage_data.get('downloadCount'),
                'referenceCount': storage_data.get('referenceCount'),
                'largeIconUrl': storage_data.get('largeIconUrl'),
                'smallIconUrl': storage_data.get('smallIconUrl'),
                'isHot': storage_data.get('isHot'),
                'cloudProvider': storage_data.get('cloudProvider'),
                'formattedSize': storage_data.get('formattedSize')
            })
        
        # 文件夹特有信息
        if self.is_folder:
            data['childrenCount'] = self.get_children_count()
            data['totalSize'] = self.get_folder_size()
        
        # 包含路径信息
        if include_path:
            data['path'] = self.get_full_path()
            data['depth'] = self.get_depth()
        
        # 包含子项信息
        if include_children and self.is_folder:
            data['children'] = [child.to_dict() for child in self.children]
        
        return data
    
    def __repr__(self):
        return f'<VirtualFile {self.id}:{self.name} (owner:{self.owner_id})>'